# -*- coding : utf-8 -*-
# @Time    : 2023/5/26 15:49
# @Author  : wanggang
# @Email   : wanggang2@lingxi.ai
# @File    : credit_sales_gpt.py
# @Software: LLM_internal

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
import os
import re
import time
import json
import copy
import tqdm
import openai
import requests
import logging
import traceback

from config import conf
from langchain import OpenAI
from treelib import Node, Tree
from openpyxl import load_workbook, Workbook
from bot.credit_sales_gpt.credit_userinfo_collector import UserInfoCollector

logging.basicConfig(format='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s',
                    level=logging.INFO)
os.environ["OPENAI_API_KEY"] = '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'
'''file_path = '/Users/lingxi/PycharmProjects/LLM_internal/internal_server/config.json'
with open(file_path, mode='r', encoding='utf-8') as f:
    config_str = f.read()
conf = json.loads(config_str)'''

'/home/work/workdir/project/LLM_internal/internal_server/bot/credit_sales_gpt/[UJD-2call-0705].xlsx'


class creditSalesGpt():

    def __init__(self):
        self.company_id = 2186
        self.tts_model = 'shutingV'

        self.task_transfer_pattern = re.compile(r'【.*】')
        task_dict, task_transfer, FAQ_off_list, FAQ_name_list, FAQ_answer_dict = self.bot_document_to_dialogue(
            '/home/work/workdir/project/LLM_internal/internal_server/bot/credit_sales_gpt/[UJD-2call-0705].xlsx')
        self.wav_dict = self.get_wav_online_content(self.company_id, self.tts_model)

        self.task_dict = task_dict
        self.task_transfer = task_transfer
        self.task_transfer_key = list(self.task_transfer.keys())

        self.FAQ_off_list = FAQ_off_list
        self.FAQ_name_list = FAQ_name_list
        self.FAQ_answer_dict = FAQ_answer_dict

        self.history_dialogue = dict()


    def llm_faq_prompt(self, content, session_id, faq_id, dialogue_faq_dict):
        if '@@quiet@@' in content.split('用户:')[-1]:
            response = '静音'
            return response

        url = 'https://ccb8is4fqtofrtdsfjebg.ml-platform-cn-beijing.volces.com/devinstance/di-20230322173305-2swjc/proxy/7173/nlu_llm?dialogue={}&tag={}'

        response = self.query('用户标签', '', url.format(content, faq_id), 'GET')
        response = json.loads(response)["result"].split('### Response:')[-1]

        if '意图' in response:
            response = response.replace('意图:', '')
        elif '情境' in response:
            response = response.replace('情境:', '')
        elif '态度' in response:
            response = response.replace('态度:', '').replace('不明', '其他')

        # 记录历史FAQ次数
        if response not in ['肯定', '否定', '其他']:
            if response not in dialogue_faq_dict:
                dialogue_faq_dict[response] = 0
            dialogue_faq_dict[response] += 1

        return response


    def faq_prompt(self, content, session_id, faq_id, dialogue_faq_dict):

        if '@@quiet@@' in content.split('用户:')[-1]:
            response = '静音'
            return response

        content = ''.join(content.replace('\\n', '').replace('万一', '').split('用户:')[1:])
        # url = 'http://8.142.8.47:8680/nlu?session_id={}&workspace={}&current_query={}&dialogue={}'
        # response = requests.get(url.format(session_id, faq_id, '0', content))
        url = 'http://8.142.85.77:8680/nlu?session_id={}&workspace={}&current_query={}'
        response = requests.get(url.format(session_id, faq_id, content))
        response = json.loads(response.text)
        intent = response['standard_query']
        attitude = response['original_attitude']
        slots = response['slot']
        slot = ''
        for slot_dict in slots:
            if slot_dict['slot_name'] in ['用款方案', '借款用途']:
                # slot = '实体：' + slot_dict['slot_value'][0]
                slot = slot_dict['slot_value'][0]

            elif (slot_dict['slot_name'] == '数字' and int(slot_dict['slot_value'][0]) > 10) or \
                    (slot_dict['slot_name'] == '价格'):
                # slot = '实体：金额'
                slot = '金额'

        if slot:
            response = slot
        elif intent and intent != 'NOINTENT':
            response = intent
        else:
            if attitude == 1:
                response = '肯定'
            elif attitude == -1:
                response = '否定'
            else:
                response = '其他'

        # 记录历史FAQ次数
        if response not in ['肯定', '否定', '其他']:
            if response not in dialogue_faq_dict:
                dialogue_faq_dict[response] = 0
            dialogue_faq_dict[response] += 1

        return response


    def dialogue_prompt(self, content, faq, task_name, history_dialogue_content):


        dialogue_list = list()
        for dialogue in self.task_dict[task_name][1]:
            if dialogue not in history_dialogue_content:
                dialogue_list.append(dialogue)
        print('过滤完选择语句:{}'.format(dialogue_list))
        print('全部选择语句:{}'.format(self.task_dict[task_name][1]))

        # '下面有一段销售员与用户对话记录，需要根据任务要求，用户的最后一句话之前的对话记录对用户的最后一句话作出任务是否完成的判断，任务未完成在"可供选择话术"中选择话术输出。需要判断任务"{}"是否完成。'
        instruction = '''任务的要求为：
{}
任务的运转逻辑是：
{}
任务的可选择话术为：
{}
你需要记住以下几点：
1.当任务的可选择话术为空时，判断任务已完成。
2.当任务的可选择话术不为空，根据对话记录，任务的要求判断任务是否完成。
3.当判断任务已完成，输出"任务完成。"。
4.当判断任务未完成，必须只能在可选择话术中选择一句话，选择的逻辑参考"任务的运转逻辑"和"任务的要求"。输出"话术："+可选择话术中选择的那句话。
输入：'''.format(self.task_dict[task_name][3], self.task_dict[task_name][4], '|'.join(dialogue_list) if dialogue_list else '', )

        content = content.split('用户：')[:-1]
        content.append(faq)
        content = '用户：'.join(content)
        # 调用大模型得到结果
        response = self.query(
            instruction, content,
            'https://ccb8is4fqtofrtdsfjebg.ml-platform-cn-beijing.volces.com/devinstance/di-20230322173305-2swjc/proxy/8200/credit_v2',
            'POST')
        print('第二次大模型prompt:{}'.format(instruction))
        print('第二次大模型输入:{}'.format(content))
        print('第二次大模型输出:{}'.format(response))


        return response

    # 将对话上下文和用户输入拼接成prompt的dict
    def generate_prompt(self, session):
        faq_query = ''
        dialogue_query = ''

        dialogue = list()
        dialogue_round = 0
        last_seat_content = ''
        for i in range(len(session)-1, -1, -1):
            session_content = session[i]
            dialogue.append(session_content)
            if session_content['role'] == 'assistant':
                dialogue_round += 1
                last_seat_content = session_content['content']

            if dialogue_round == 1:
                break

        dialogue.reverse()
        for session_content in dialogue:
            if session_content['role'] == 'user':
                faq_query += '用户:{}\\n'.format(session_content['content'])
            elif session_content['role'] == 'assistant':
                faq_query += '销售员:{}\\n'.format(session_content['content'].split('@')[-1].split('，')[-1])
                # faq_query += '销售员:{}\\n'.format(session_content['content'].split('@')[-1])

        dialogue = list()
        dialogue_round = 0
        for i in range(len(session)-1, -1, -1):
            session_content = session[i]
            dialogue.append(session_content)
            if session_content['role'] == 'assistant':
                dialogue_round += 1

            if dialogue_round == 2:
                break

        dialogue.reverse()
        for session_content in dialogue:
            if session_content['role'] == 'user':
                dialogue_query += '用户：{}\n'.format(session_content['content'])
            elif session_content['role'] == 'assistant':
                dialogue_query += '销售员：{}\n'.format(session_content['content'].split('@')[-1])

        return faq_query, dialogue_query, last_seat_content


    def get_seat_response(self, task_name, faq_response):

        faq_seat_response = ''
        if 'faq答案' in task_name:
            task_name = task_name.replace('faq答案+', '')

            if faq_response in self.FAQ_answer_dict:
                faq_seat_response = self.FAQ_answer_dict[faq_response][2] + '@#' + \
                                    self.FAQ_answer_dict[faq_response][1] + '||' + \
                                    self.FAQ_answer_dict[faq_response][0] + '#@'

        # new
        if faq_response not in self.task_dict[task_name][0]:
            simple_seat_response, seat_response = self.task_dict[task_name][0]['首句']
        else:
            simple_seat_response, seat_response = self.task_dict[task_name][0][faq_response]

        return simple_seat_response, faq_seat_response, seat_response



    def choise_next_task(self, task, faq_response):

        if task + '+' + faq_response in self.task_transfer_key:
            return self.task_transfer[task + '+' + faq_response]
        else:
            return self.task_transfer[task+'+FAQ']

    # 历史记录获取
    def get_session(self, user_id):

        session = self.history_dialogue[user_id]['session']
        session_dialogue = self.history_dialogue[user_id]['sessionDialogue']
        online_task_list = self.history_dialogue[user_id]['onlineTaskList']
        finish_task_list = self.history_dialogue[user_id]['finishTaskList']
        dialogue_faq_dict = self.history_dialogue[user_id]['dialogueFaqDict']
        history_dialogue_content = self.history_dialogue[user_id]['historyDialogueContent']

        return session, session_dialogue, online_task_list, \
               finish_task_list, dialogue_faq_dict, history_dialogue_content

    # 历史记录保存
    def push_session(self, user_id, session, session_dialogue,
                     online_task_list, finish_task_list, dialogue_faq_dict, history_dialogue_content):

        # self.history_dialogue[user_id] = session, session_dialogue
        self.history_dialogue[user_id] = {
            'session': session,
            'sessionDialogue': session_dialogue,
            'onlineTaskList': online_task_list,
            'finishTaskList': finish_task_list,
            'dialogueFaqDict': dialogue_faq_dict,
            'historyDialogueContent': history_dialogue_content,
        }


    # 运行入口
    def reply(self, user_content, user_id):

        if user_content:
            session, session_dialogue, online_task_list, \
            finish_task_list, dialogue_faq_dict, history_dialogue_content = self.get_session(user_id)
            session_copy = copy.deepcopy(session)
            session_copy.append({'role': 'user', 'content': user_content})
            session_dialogue.append({'role': 'user', 'content': user_content})

            task_name = online_task_list[0]

            faq_query, dialogue_query, last_seat_content = self.generate_prompt(session_dialogue)
            faq_response = self.faq_prompt(faq_query, '-1', '222', dialogue_faq_dict)
            print('第一次大模型输入:{}'.format(faq_query))
            print('第一次大模型输出:{}'.format(faq_response))
            session_copy[-1]['content'] = faq_response
            session_dialogue[-1]['content'] = faq_response
            dialogue_response = self.dialogue_prompt(dialogue_query, faq_response,
                                                    task_name, history_dialogue_content)

            if '任务完成' in dialogue_response:
                finish_task_list.append(task_name)
                next_task = self.choise_next_task(task_name, faq_response)
                simple_seat_content, faq_seat_response, seat_content = self.get_seat_response(next_task, faq_response)

                if faq_response in self.FAQ_off_list:
                    seat_content = faq_seat_response
                elif self.task_dict[task_name][6][self.task_dict[task_name][1].index(last_seat_content)]:
                    dialogue_label = self.task_dict[task_name][6][self.task_dict[task_name][1].index(last_seat_content)]
                    seat_content = faq_seat_response+seat_content.split('》')[0]+'》'+dialogue_label.replace('标签', faq_response.split('-')[0])+seat_content.split('》')[1]
                else:
                    seat_content = faq_seat_response+seat_content.replace('标签', faq_response.split('-')[0])
                session_copy.append({'role': 'assistant', 'content': simple_seat_content})
                session_dialogue = [{'role': 'assistant', 'content': simple_seat_content}, ]
                return_seat_content = 'faq名称：{}\n完成阶段：{}\n接下来进入阶段：{}\n坐席话术为：{}'.format(
                    faq_response, task_name, next_task, seat_content)
                online_task_list[0] = next_task.replace('faq答案+', '')
            else:
                print('简版选择语句:{}'.format(self.task_dict[task_name][1]))
                print('完整选择语句:{}'.format(self.task_dict[task_name][2]))
                print('录音编号存储字典:{}'.format(self.task_dict[task_name][7]))
                simple_seat_content = dialogue_response.split('话术：')[-1].replace('\n', '')

                if simple_seat_content not in self.task_dict[task_name][1]:
                    print('第二次大模型结果:{}。不在待选择话术中'.format(simple_seat_content))

                seat_content = self.task_dict[task_name][2][self.task_dict[task_name][1].index(simple_seat_content)]
                seat_content = seat_content.replace(
                    '标签', faq_response.split('-')[0] if '-' in faq_response else faq_response)

                # 根据简版话术+用户标签，得到对应录音编号
                wav_no_key = simple_seat_content + faq_response if 'faq' not in simple_seat_content else simple_seat_content + 'faq'
                if wav_no_key in self.task_dict[task_name][7]:
                    seat_content = seat_content.replace(
                        '[录音编号]',
                        self.task_dict[task_name][7][wav_no_key])
                else:
                    seat_content = seat_content.replace(
                        '[录音编号]',
                        self.task_dict[task_name][7][simple_seat_content])

                if '【faq答案】+' in seat_content:
                    faq_response = faq_response + '轮询' if faq_response + '轮询' in self.FAQ_answer_dict and \
                                                          dialogue_faq_dict.get(faq_response, 1) >= 2 else faq_response
                    if faq_response in self.FAQ_answer_dict:
                        if faq_response in self.FAQ_off_list:
                            seat_content = self.FAQ_answer_dict[faq_response][2] + '@#' + \
                                           self.FAQ_answer_dict[faq_response][1] + \
                                           '||' + self.FAQ_answer_dict[faq_response][0] + '@#'
                        else:
                            seat_content = self.FAQ_answer_dict[faq_response][2] + '@#' + \
                                           self.FAQ_answer_dict[faq_response][1] + \
                                           '||' + self.FAQ_answer_dict[faq_response][0] + '@#' + seat_content.replace(
                                '【faq答案】+', '')
                    else:
                        seat_content = seat_content.replace('【faq答案】+', '')

                # 插入对应存储单元
                session_copy.append({'role': 'assistant', 'content': simple_seat_content})
                session_dialogue.append({'role': 'assistant', 'content': simple_seat_content})
                return_seat_content = 'faq名称：{}\n当前所属阶段为：{}\n坐席话术为：{}'.format(
                    faq_response, task_name, seat_content)
        else:
            simple_seat_content, faq_seat_response, seat_content = self.get_seat_response('核身', '首句')
            session_copy = [{'role': 'assistant', 'content': simple_seat_content,}]
            session_dialogue = [{'role': 'assistant', 'content': simple_seat_content,}]
            online_task_list = ['核身', ]
            finish_task_list = list()
            dialogue_faq_dict = dict()
            history_dialogue_content = ''

            return_seat_content = 'faq名称：{}\n当前所属阶段为：{}\n坐席话术为：{}'.format(
                '', online_task_list[0], seat_content)
        history_dialogue_content = history_dialogue_content+';'+simple_seat_content

        self.push_session(user_id, session_copy, session_dialogue,
                          online_task_list, finish_task_list, dialogue_faq_dict, history_dialogue_content)
        print('全局对话记录:{}'.format(session_copy))
        print('大模型对话记录:{}'.format(session_dialogue))
        print('后续任务名称:{}'.format(online_task_list))
        print('已完成任务名称:{}'.format(finish_task_list))
        print('FAQ计数:{}'.format(dialogue_faq_dict))
        print('返回结果:{}'.format(return_seat_content))
        return return_seat_content

    # 调用模型完成识别
    def query(self, instruction, input_data, url, request_type):
        if not instruction:
            return '任务完成'

        headers = {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
            'Accept-Encoding': 'gzip, deflate, br',
            'Accept-Language': 'zh-CN,zh;q=0.9',
            'Cookie': 'code-server-session=6ed9af325f2b7ec3c8a1d02651d816cdc5390e3192298a2ba25d02f1b9fcdac6',
        }
        if request_type == 'POST':
            data = json.dumps({
                'instruction': instruction,
                'input': input_data,
            })
            response = requests.post(
                url,
                headers=headers,
                json=data
            ).text
        elif request_type == 'GET':
            response = requests.get(url, headers=headers).text

        return response


    def bot_document_to_dialogue(self, file_path):
        wb = load_workbook(file_path)
        ws = wb[wb.sheetnames[2]]
        FAQ_off_list, FAQ_name_list, FAQ_answer_dict = self.bot_document_to_faq(file_path)

        task_transfer = dict()
        task_dict = dict()
        task_name = ''
        slot_id = 1
        for i, row in enumerate(ws.values):
            task_logic = row[0]
            task_name = row[1] if row[1] else task_name
            task_stage = str(row[4])
            task_condition = row[5]
            task_wav_no = row[6]
            task_seat_response = row[7]
            # task_seat_response = '流程节点录音编号对应内容'
            task_simple_seat_response = row[8]
            task_label = '['+row[9]+']' if row[9] else ''
            task_sign = row[13]
            task_response_label = '['+row[10]+']' if row[10] else ''

            # 初始化任务
            if task_name not in task_dict:
                task_dict[task_name] = [
                    # 进入条件
                    dict(),
                    # 可选择的简版回复话术
                    list(),
                    # 真实完整的回复话术
                    list(),
                    # 任务是否完成的判断逻辑
                    task_logic.split('\n')[0],
                    # 任务运转逻辑
                    task_logic.split('\n')[1],
                    # 以树结构保存的流程路线
                    list(),
                    # 语句对应的标签可为空值
                    list(),
                    # 录音编号的多重选择
                    dict(),
                ]

            # 构建任务字典，任务转换字典
            if '.' not in task_stage:
                task_conditions = task_condition.split('\n') if '\n' in task_condition else [task_condition, ]
                for condition in task_conditions:
                    task_dict[task_name][0][condition] = [task_simple_seat_response,
                                                          '《槽位id:{}》'.format(slot_id)+'@#'+task_wav_no+'||'+task_seat_response+'#@']
                    task_dict[task_name][1].append(task_simple_seat_response)
                    task_dict[task_name][2].append(
                        '《槽位id:{}》'.format(slot_id) + '@#' + task_wav_no + '||' + task_seat_response + '#@@@end@@@@notbreak@@' \
                        if task_sign == '挂机' else \
                        '《槽位id:{}》'.format(slot_id) + '@#' + task_wav_no + '||' + task_seat_response + '#@')

                    task_dict[task_name][6].append(task_response_label)
                    slot_id += 1

            elif '【' in task_simple_seat_response and '】' in task_simple_seat_response:
                result = self.task_transfer_pattern.search(task_simple_seat_response)

                if result.group() == '【faq答案】' and \
                        task_simple_seat_response.replace('【faq答案】+', 'faq答案') not in task_dict[task_name][1]:
                    task_dict[task_name][1].append(task_simple_seat_response.replace('【faq答案】+', 'faq答案'))
                    task_dict[task_name][2].append(
                        '《槽位id:{}》'.format(slot_id) + task_label + '@#' + '[录音编号]' + '||' + task_seat_response + '#@@@end@@@@notbreak@@' \
                        if task_sign == '挂机' else \
                        '《槽位id:{}》'.format(slot_id) + task_label + '@#' + '[录音编号]' + '||' + task_seat_response + '#@')
                    task_dict[task_name][6].append(task_response_label)
                    task_dict[task_name][7][task_simple_seat_response.replace('【faq答案】+', 'faq答案')+'faq'] = task_wav_no
                    task_dict[task_name][7][task_simple_seat_response.replace('【faq答案】+', 'faq答案')] = task_wav_no
                    slot_id += 1
                else:
                    result = result.group().replace('【', '').replace('】', '')
                    if '\n' in task_condition:
                        for condition in task_condition.split('\n'):
                            task_transfer[task_name + '+' + condition] = result
                    elif '|' in task_condition: # FAQ|非本人操作
                        task_transfer[task_name + '+' + task_condition.split('|')[0]] = result
                    else:
                        task_transfer[task_name + '+' + task_condition] = result
            elif task_simple_seat_response not in task_dict[task_name][1]:
                task_dict[task_name][1].append(task_simple_seat_response)
                task_dict[task_name][2].append(
                    '《槽位id:{}》'.format(slot_id) + task_label + '@#' + '[录音编号]' + '||' + task_seat_response + '#@@@end@@@@notbreak@@' \
                    if task_sign == '挂机' else \
                    '《槽位id:{}》'.format(slot_id) + task_label + '@#' + '[录音编号]' + '||' + task_seat_response + '#@')
                task_dict[task_name][6].append(task_response_label)
                task_dict[task_name][7][task_simple_seat_response+task_condition] = task_wav_no
                task_dict[task_name][7][task_simple_seat_response] = task_wav_no
                slot_id += 1
            elif task_simple_seat_response in task_dict[task_name][1]:
                task_dict[task_name][7][task_simple_seat_response+task_condition] = task_wav_no
                task_dict[task_name][7][task_simple_seat_response] = task_wav_no

        return task_dict, task_transfer, FAQ_off_list, FAQ_name_list, FAQ_answer_dict


    def bot_document_to_faq(self, file_path):
        wb = load_workbook(file_path)
        ws = wb[wb.sheetnames[1]]

        FAQ_answer_dict = dict()
        FAQ_name_list = list()
        FAQ_off_list = list()
        for i, row in tqdm.tqdm(enumerate(ws.values)):
            if i != 0:
                faq_name = row[0]
                faq_wav_no = row[1]
                faq_label = row[2]
                faq_seat_response = row[3]
                faq_sign = row[5]

                FAQ_answer_dict[faq_name] = [faq_seat_response, faq_wav_no, '['+faq_label+']']

                if '轮询' not in faq_name and faq_sign != '挂机':
                    FAQ_name_list.append(faq_name)
                if faq_sign == '挂机':
                    FAQ_off_list.append(faq_name)
                    FAQ_answer_dict[faq_name][-1] += '[挂机]'
                    FAQ_answer_dict[faq_name][0] += '@@end@@@@notbreak@@'

        return FAQ_off_list, FAQ_name_list, FAQ_answer_dict


    def get_wav_online_content(self, company_id, tts_model):
        url = 'http://work.xi-ai.com/admin/soundRecording/getRecordManageList?companyId={}&ttsModel={}'.format(company_id,
                                                                                                               tts_model)
        wav_key = '{}_{}'.format(company_id, tts_model)
        wav_dict = {
            wav_key: dict()
        }
        try:
            response = json.loads(requests.get(url).text)

            for wav_data in response['data'][0]['list']:
                file_name = wav_data['fileName']
                content = wav_data['content']
                wav_dict[wav_key][file_name] = content

            return wav_dict
        except Exception as err:
            traceback.print_exc()




def test():
    conversation = creditSalesGpt()
    UserInfoCollector_query = UserInfoCollector()

    print(conversation.reply('', '11111'))
    print(conversation.history_dialogue)
    print(conversation.reply('是的', '11111'))
    print(conversation.history_dialogue)
    print(conversation.reply('好的', '11111'))
    print(conversation.history_dialogue)
    print(conversation.reply('好的', '11111'))
    print(conversation.history_dialogue)
    print(conversation.reply('好的', '11111'))
    print(conversation.history_dialogue)
    print(conversation.reply('不用', '11111'))
    print(conversation.history_dialogue)






if __name__ == '__main__':

    # define_DM()
    # define_task()
    # test()

    for i in range(11, 0, -1):
        print(i)











